<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>The source code</title>
  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  <style type="text/css">
    .highlight { display: block; background-color: #ddd; }
  </style>
  <script type="text/javascript">
    function highlight() {
      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
    }
  </script>
</head>
<body onload="prettyPrint(); highlight();">
  <pre class="prettyprint lang-js"><span id='global-property-'>/**
</span> * @ignore
 * write html into its minified form,thanks to kangax where minify algorithm comes from
 * @author yiminghe@gmail.com
 */
KISSY.add(&quot;html-parser/writer/minify&quot;, function (S, BasicWriter, Utils) {
    var trim = S.trim,
        isBooleanAttribute = Utils.isBooleanAttribute,
        collapseWhitespace = Utils.collapseWhitespace,
        reEmptyAttribute = new RegExp(
            '^(?:class|id|style|title|lang|dir|on' +
                '(?:focus|blur|change|click|dblclick|mouse(' +
                '?:down|up|over|move|out)|key(?:press|down|up)))$');

    function escapeAttrValue(str) {
        return String(str).replace(/&quot;/g, &quot;&amp;quote;&quot;);
    }

    function canDeleteEmptyAttribute(tag, attr) {
        var attrValue = attr.value || &quot;&quot;,
            attrName = attr.name;
        if (!trim(attrValue)) {
            return ((tag === 'input' &amp;&amp; attrName === 'value') ||
                reEmptyAttribute.test(attrName));
        }
        return 0;
    }


    function canRemoveAttributeQuotes(value) {
        // http://www.w3.org/TR/html5/syntax.html#unquoted
        // avoid \w, which could match unicode in some implementations
        return !(/[ &quot;'=&lt;&gt;`]/).test(value);
    }

    function isAttributeRedundant(el, attr) {
        var tag = el.nodeName,
            attrName = attr.name,
            attrValue = attr.value || &quot;&quot;;
        attrValue = trim(attrValue.toLowerCase());
        return (
            (tag === 'script' &amp;&amp;
                attrName === 'language' &amp;&amp;
                attrValue === 'javascript') ||

                (tag === 'form' &amp;&amp;
                    attrName === 'method' &amp;&amp;
                    attrValue === 'get') ||

                (tag === 'input' &amp;&amp;
                    attrName === 'type' &amp;&amp;
                    attrValue === 'text') ||

                (tag === 'script' &amp;&amp;
                    attrName === 'type' &amp;&amp;
                    attrValue === 'text/javascript') ||

                (tag === 'style' &amp;&amp;
                    attrName === 'type' &amp;&amp;
                    attrValue === 'text/css') ||

                (tag === 'area' &amp;&amp;
                    attrName === 'shape' &amp;&amp;
                    attrValue === 'rect')
            );
    }

    function isConditionalComment(text) {
        return (/\[if[^\]]+\]/).test(text);
    }

    function isEventAttribute(attrName) {
        return (/^on[a-z]+/).test(attrName);
    }

    function isUriTypeAttribute(attrName, tag) {
        return (
            ((/^(?:a|area|link|base)$/).test(tag) &amp;&amp; attrName === 'href') ||
                (tag === 'img' &amp;&amp; (/^(?:src|longdesc|usemap)$/).test(attrName)) ||
                (tag === 'object' &amp;&amp; (/^(?:classid|codebase|data|usemap)$/).test(attrName)) ||
                (tag === 'q' &amp;&amp; attrName === 'cite') ||
                (tag === 'blockquote' &amp;&amp; attrName === 'cite') ||
                ((tag === 'ins' || tag === 'del') &amp;&amp; attrName === 'cite') ||
                (tag === 'form' &amp;&amp; attrName === 'action') ||
                (tag === 'input' &amp;&amp; (attrName === 'src' || attrName === 'usemap')) ||
                (tag === 'head' &amp;&amp; attrName === 'profile') ||
                (tag === 'script' &amp;&amp; (attrName === 'src' || attrName === 'for'))
            );
    }

    function isNumberTypeAttribute(attrName, tag) {
        return (
            ((/^(?:a|area|object|button)$/).test(tag) &amp;&amp; attrName === 'tabindex') ||
                (tag === 'input' &amp;&amp; (attrName === 'maxlength' || attrName === 'tabindex')) ||
                (tag === 'select' &amp;&amp; (attrName === 'size' || attrName === 'tabindex')) ||
                (tag === 'textarea' &amp;&amp; (/^(?:rows|cols|tabindex)$/).test(attrName)) ||
                (tag === 'colgroup' &amp;&amp; attrName === 'span') ||
                (tag === 'col' &amp;&amp; attrName === 'span') ||
                ((tag === 'th' || tag == 'td') &amp;&amp; (attrName === 'rowspan' || attrName === 'colspan'))
            );
    }

    function cleanAttributeValue(el, attr) {
        var tag = el.nodeName,
            attrName = attr.name,
            attrValue = attr.value || &quot;&quot;;
        if (isEventAttribute(attrName)) {
            attrValue = trim(attrValue)
                .replace(/^javascript:[\s\xa0]*/i, '')
                .replace(/[\s\xa0]*;$/, '');
        }
        else if (attrName === 'class') {
            attrValue = collapseWhitespace(trim(attrValue));
        }
        else if (isUriTypeAttribute(attrName, tag) ||
            isNumberTypeAttribute(attrName, tag)) {
            attrValue = trim(attrValue);
        }
        else if (attrName === 'style') {
            attrValue = trim(attrValue).replace(/[\s\xa0]*;[\s\xa0]*$/, '');
        }
        return attrValue;
    }

    function cleanConditionalComment(comment) {
        return comment
            .replace(/^(\[[^\]]+\]&gt;)[\s\xa0]*/, '$1')
            .replace(/[\s\xa0]*(&lt;!\[endif\])$/, '$1');
    }

    function removeCDATASections(text) {
        return trim(text)
            // &quot;/* &lt;![CDATA[ */&quot; or &quot;// &lt;![CDATA[&quot;
            .replace(/^(?:[\s\xa0]*\/\*[\s\xa0]*&lt;!\[CDATA\[[\s\xa0]*\*\/|[\s\xa0]*\/\/[\s\xa0]*&lt;!\[CDATA\[.*)/, '')// [\s\xa0]* ??
            // &quot;/* ]]&gt; */&quot; or &quot;// ]]&gt;&quot;
            .replace(/(?:\/\*[\s\xa0]*\]\]&gt;[\s\xa0]*\*\/|\/\/[\s\xa0]*\]\]&gt;)[\s\xa0]*$/, '');
    }

<span id='KISSY-HtmlParser-MinifyWriter'>    /**
</span>     * MinifyWriter for html content
     * @class KISSY.HtmlParser.MinifyWriter
     * @extends KISSY.HtmlParser.BasicWriter
     */
    function MinifyWriter() {
        var self = this;
        MinifyWriter.superclass.constructor.apply(self, arguments);
        self.inPre = 0;
    }

    S.extend(MinifyWriter, BasicWriter, {
<span id='KISSY-HtmlParser-MinifyWriter-method-comment'>        /**
</span>         * remove non-conditional comment
         */
        comment: function (text) {
            if (isConditionalComment(text)) {
                text = cleanConditionalComment(text);
                MinifyWriter.superclass.comment.call(this, text);
            }
        },

<span id='KISSY-HtmlParser-MinifyWriter-method-openTag'>        /**
</span>         * record pre track
         */
        openTag: function (el) {
            var self = this;
            if (el.tagName == 'pre') {
                self.inPre = 1;
            }
            MinifyWriter.superclass.openTag.apply(self, arguments);
        },

<span id='KISSY-HtmlParser-MinifyWriter-method-closeTag'>        /**
</span>         * clean pre track
         */
        closeTag: function (el) {
            var self = this;
            if (el.tagName == 'pre') {
                self.inPre = 0;
            }
            MinifyWriter.superclass.closeTag.apply(self, arguments);
        },

<span id='KISSY-HtmlParser-MinifyWriter-method-cdata'>        /**
</span>         * textarea | script | style
         */
        cdata: function (cdata) {
            cdata = removeCDATASections(cdata);
            MinifyWriter.superclass.cdata.call(this, cdata);
        },

        attribute: function (attr, el) {
            var self = this,
                name = attr.name,
                normalizedValue,
                value = attr.value || &quot;&quot;;

            // remove empty attribute
            if (canDeleteEmptyAttribute(el, attr) ||
                // remove redundant attribute
                isAttributeRedundant(el, attr)) {
                return;
            }

            if (isBooleanAttribute(name)) {
                // collapse boolean attributes
                self.append(&quot; &quot;, name);
                return;
            }

            // clean attribute value
            normalizedValue = escapeAttrValue(cleanAttributeValue(el, attr));

            if (value &amp;&amp; canRemoveAttributeQuotes(value)) {
                // remove quote if value is not empty
            } else {
                normalizedValue = '&quot;' + normalizedValue + '&quot;';
            }

            self.append(&quot; &quot;, name, &quot;=&quot;, normalizedValue);
        },

<span id='KISSY-HtmlParser-MinifyWriter-method-text'>        /**
</span>         * note : pre is special
         */
        text: function (text) {
            var self = this;
            if (!self.inPre) {
                // collapse whitespace
                text = collapseWhitespace(text);
            }
            self.append(text);
        }
    });

    return MinifyWriter;
}, {
    requires: ['./basic', '../utils']
});

/*
 refer :
 - https://github.com/kangax/html-minifier/
 */</pre>
</body>
</html>
